package config

import (
	"encoding/base64"
	"strconv"
	"strings"
	"sync"
	"unicode"

	"gitee.com/haodreams/libs/aescry"
)

var key = aescry.MakeKey("key@123")

// 程序启动前必须设置加密key
func SetKey(k string) {
	key = aescry.MakeKey(k)
}

func GetKey() string {
	return key
}

// 解密字符串
// 支持2种方式解密 ENC: ENCRYPT:
func DecodeValue(value string) string {
	if val := string(value); strings.HasPrefix(val, "ENC:") {
		val = strings.TrimPrefix(val, "ENC:")
		val, err := base64.StdEncoding.DecodeString(val)
		if err != nil {
			return value
		}
		v, err := aescry.Decrypt([]byte(val), []byte(GetKey()))
		if err != nil {
			return string(value)
		}
		return string(v)
	}
	if val := string(value); strings.HasPrefix(val, "ENCRYPT:") {
		val = strings.TrimPrefix(val, "ENCRYPT:")
		val, err := base64.StdEncoding.DecodeString(val)
		if err != nil {
			return value
		}
		v, err := aescry.Decrypt([]byte(val), []byte(GetKey()))
		if err != nil {
			return string(value)
		}
		return string(v)
	}
	return value
}

// 加密字符串 优先ENC
func EncodeValue(value string) string {
	if strings.HasPrefix(value, "ENC:") {
		return value //已经加密过不需要加密
	}

	if strings.HasPrefix(value, "ENCRYPT:") {
		return value //已经加密过不需要加密
	}

	val, err := aescry.Encrypt([]byte(value), []byte(GetKey()))
	if err != nil {
		return value
	}
	return "ENC:" + base64.StdEncoding.EncodeToString(val)
}

// Conf .
type Conf struct {
	kv         map[string]*KV
	lock       sync.RWMutex
	driverName string
	kvs        []*KV //配置列表
}

// Lock 加锁
func (m *Conf) Lock() {
	m.lock.Lock()
}

// Unlock 释放锁
func (m *Conf) Unlock() {
	m.lock.Unlock()
}

// SetList .
func (m *Conf) SetList(kvs []*KV) {
	m.lock.Lock()
	defer m.lock.Unlock()
	m.kv = map[string]*KV{}
	m.kvs = make([]*KV, 0, len(kvs))
	for _, kv := range kvs {
		kv.Value = DecodeValue(kv.Value)
		v, ok := m.kv[kv.Name]
		if ok && v != nil {
			*v = *kv
			continue
		}
		m.kv[kv.Name] = kv
		m.kvs = append(m.kvs, kv)
	}
}

// SetDriverName .
func (m *Conf) SetDriverName(name string) {
	m.driverName = name
}

// GetDriverName .
func (m *Conf) GetDriverName() string {
	return m.driverName
}

func (m *Conf) SetMap(mp map[string]string) {
	m.lock.Lock()
	defer m.lock.Unlock()

	if m.kv == nil {
		m.kv = map[string]*KV{}
	}
	for key, value := range mp {
		kv := new(KV)
		kv.Name = key
		kv.Value = value
		m.kv[key] = kv
	}
}

// Set
func (m *Conf) Set(key, value, desc string) (err error) {
	m.lock.Lock()
	defer m.lock.Unlock()
	kv := new(KV)
	kv.Name = key
	kv.Value = value
	kv.Desc = desc
	if m.kv == nil {
		m.kv = map[string]*KV{}
	} else {
		if v, ok := m.kv[key]; ok && v != nil {
			v.Value = value
			v.Desc = strings.TrimFunc(desc, unicode.IsSpace) + "  \n"
			return
		}
	}
	m.kv[key] = kv
	m.kvs = append(m.kvs, kv)
	return
}

// Set
func (m *Conf) SetValue(key, value string) (err error) {
	m.lock.Lock()
	defer m.lock.Unlock()
	kv := new(KV)
	kv.Name = key
	kv.Value = value
	if m.kv == nil {
		m.kv = map[string]*KV{}
	} else {
		if v, ok := m.kv[key]; ok && v != nil {
			v.Value = value
			return
		}
	}
	m.kv[key] = kv
	return
}

func (m *Conf) SetWidthOption(key, value, desc, option string) (err error) {
	m.lock.Lock()
	defer m.lock.Unlock()
	kv := new(KV)
	kv.Name = key
	kv.Value = value
	kv.Desc = desc
	kv.Opts = option
	if m.kv == nil {
		m.kv = map[string]*KV{}
	} else {
		if v, ok := m.kv[key]; ok && v != nil {
			v.Value = value
			v.Desc = desc
			v.Opts = option
			return
		}
	}
	m.kv[key] = kv
	return
}

func (m *Conf) Get(key string) KValuer {
	m.lock.RLock()
	defer m.lock.RUnlock()
	if kv, ok := m.kv[key]; ok {
		return kv
	}
	return nil
}

// String .
func (m *Conf) String(key string) string {
	m.lock.RLock()
	defer m.lock.RUnlock()
	if kv, ok := m.kv[key]; ok {
		return kv.Value
	}
	return ""
}

// DefaultString .
func (m *Conf) DefaultString(key string, defaultValue string) string {
	m.lock.RLock()
	defer m.lock.RUnlock()
	if kv, ok := m.kv[key]; ok {
		if kv.Value == "" {
			return defaultValue
		}

		return kv.Value
	}
	return defaultValue
}

// Int .
func (m *Conf) Int(key string) (val int, err error) {
	m.lock.RLock()
	defer m.lock.RUnlock()
	if kv, ok := m.kv[key]; ok {
		val, err = strconv.Atoi(kv.Value)
		return
	}
	return
}

// DefaultInt .
func (m *Conf) DefaultInt(key string, defaultValue int) int {
	m.lock.RLock()
	defer m.lock.RUnlock()
	if kv, ok := m.kv[key]; ok {
		val, err := strconv.Atoi(kv.Value)
		if err != nil {
			return defaultValue
		}
		return val
	}
	return defaultValue
}

// Int64 .
func (m *Conf) Int64(key string) (val int64, err error) {
	m.lock.RLock()
	defer m.lock.RUnlock()
	if kv, ok := m.kv[key]; ok {
		val, err = strconv.ParseInt(kv.Value, 10, 64)
		return
	}
	return
}

// DefaultInt64 .
func (m *Conf) DefaultInt64(key string, defaultValue int64) int64 {
	m.lock.RLock()
	defer m.lock.RUnlock()
	if kv, ok := m.kv[key]; ok {
		val, err := strconv.ParseInt(kv.Value, 10, 64)
		if err != nil {
			return defaultValue
		}
		return val
	}
	return defaultValue
}

// UInt .
func (m *Conf) UInt(key string) (val uint64, err error) {
	m.lock.RLock()
	defer m.lock.RUnlock()
	if kv, ok := m.kv[key]; ok {
		val, err = strconv.ParseUint(kv.Value, 10, 64)
		return
	}
	return
}

// DefaultUInt .
func (m *Conf) DefaultUInt(key string, defaultValue uint64) uint64 {
	m.lock.RLock()
	defer m.lock.RUnlock()
	if kv, ok := m.kv[key]; ok {
		val, err := strconv.ParseUint(kv.Value, 10, 64)
		if err != nil {
			return defaultValue
		}
		return val
	}
	return defaultValue
}

// Float .
func (m *Conf) Float(key string) (val float64, err error) {
	m.lock.RLock()
	defer m.lock.RUnlock()
	if kv, ok := m.kv[key]; ok {
		val, err = strconv.ParseFloat(kv.Value, 64)
		return
	}
	return
}

// DefaultFloat .
func (m *Conf) DefaultFloat(key string, defaultValue float64) float64 {
	m.lock.RLock()
	defer m.lock.RUnlock()
	if kv, ok := m.kv[key]; ok {
		val, err := strconv.ParseFloat(kv.Value, 64)
		if err != nil {
			return defaultValue
		}
		return val
	}
	return defaultValue
}

// Float32 .
func (m *Conf) Float32(key string) (val float32, err error) {
	v, err := m.Float(key)
	if err != nil {
		return
	}

	return float32(v), err
}

// DefaulFloat32 .
func (m *Conf) DefaulFloat32(key string, defaultValue float32) float32 {
	return float32(m.DefaultFloat(key, float64(defaultValue)))
}

// List 获取列表
func (m *Conf) List() []*KV {
	return m.kvs
}

// Bool .
func (m *Conf) Bool(key string) (bool, error) {
	m.lock.RLock()
	defer m.lock.RUnlock()
	if kv, ok := m.kv[key]; ok {
		val := strings.ToUpper(kv.Value)
		val = strings.TrimSpace(val)
		switch val {
		case "TRUE", "Y", "ON", "YES", "1":
			return true, nil
		default:
			return false, nil
		}
	}
	return false, nil
}

// DefaultBool .
func (m *Conf) DefaultBool(key string, defaultValue bool) bool {
	m.lock.RLock()
	defer m.lock.RUnlock()
	if kv, ok := m.kv[key]; ok {
		val := strings.ToUpper(kv.Value)
		val = strings.TrimSpace(val)
		switch val {
		case "TRUE", "Y", "ON", "YES", "1":
			return true
		}
		return false
	}
	return defaultValue
}
